/**
 * 
 */
package com.shiplanet.service.impl;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.shiplanet.dao.CategoryDAO;
import com.shiplanet.dao.PhotoDAO;
import com.shiplanet.dao.PostDAO;
import com.shiplanet.entity.Category;
import com.shiplanet.entity.Photo;
import com.shiplanet.entity.Post;
import com.shiplanet.service.CategoryService;
import com.shiplanet.util.Constants;

/**
 * @author joesong
 *
 */
@Service("categoryService")
public class CategoryServiceImpl implements CategoryService {
	@Resource
	private CategoryDAO categoryDAO;

	@Resource
	private PostDAO postDAO;

	@Resource
	private PhotoDAO photoDAO;

	public Category getCategory(Integer categoryId) {
		return categoryDAO.get(Category.class, categoryId);
	}

	public Integer saveCategoryWithPhoto(Category category, File[] photoFiles,
			String realRootPath) throws Exception {

		addCategoryPhotoFiles(category, photoFiles, realRootPath);

		return (Integer) categoryDAO.save(category);
	}

	public void deleteCategoryWithPhoto(Category category, String realRootPath) {
		// disconnect all posts under this category or its sub category
		removePosts(category);

		// delete all photo files for each category
		deleteCategoryPhotoFiles(category, realRootPath);

		// delete records in database
		categoryDAO.delete(category);
	}

	public void updateCategoryWithPhoto(Category originalCategory, Category newCategory, File[] photoFiles,
			String realRootPath) throws Exception {
		// update category fields
		originalCategory.setName(newCategory.getName());
		originalCategory.setDescription(newCategory.getDescription());
		originalCategory.setPopular(newCategory.isPopular());
		
		// delete photo files for this category
		if (photoFiles != null && originalCategory.getPhotos() != null) {
			Iterator<Photo> it = originalCategory.getPhotos().iterator();
			while (it.hasNext()) {
				Photo photo = it.next();
				File photoFile = new File(realRootPath + photo.getURL());
				photoFile.delete();
				photo.setCategory(null);
				it.remove();
			}
		}
		
		// add new photo files for this category
		addCategoryPhotoFiles(originalCategory, photoFiles, realRootPath);

		categoryDAO.update(originalCategory);
	}

	public List<Category> findRootCategories() {
		return categoryDAO.findRootCategories();
	}

	public List<Category> findPopularCategories() {
		return categoryDAO.findPopularCategories();
	}

	public void iterateCategory(Category category, Command command) {
		if (category != null) {
			command.execute(category);
			if (category.getChildren() != null)
				for (Category cat : category.getChildren()) {
					iterateCategory(cat, command);
				}
		}
	}

	private void setCategoryNameMap(final Map<Integer, String> map,
			Category category, final boolean isFullName) {
		iterateCategory(category, new Command() {
			public void execute(Category cat) {
				if (isFullName) {
					String name = cat.getName();
					Category parent = cat.getParent();
					if (parent != null) {
						name = map.get(parent.getId()) + "->" + cat.getName();
					}
					map.put(cat.getId(), name);
				} else {
					map.put(cat.getId(), cat.getName());
				}
			}
		});
	}

	public Map<Integer, String> getCategoryNameMap(boolean isFullName,
			boolean isRootLevel) {
		List<Category> catList = findRootCategories();

		Map<Integer, String> map = new TreeMap<Integer, String>();

		if (isRootLevel) {
			for (Category cat : catList) {
				map.put(cat.getId(), cat.getName());
			}
		} else {

			for (Category cat : catList) {
				setCategoryNameMap(map, cat, isFullName);
			}
		}

		return map;
	}

	public void removePosts(Category category) {
		List<Category> catList = findSubCategories(category);
		categoryDAO.removePostsByCategory(catList);
	}

	public List<Post> findPostsByCategory(Category category) {
		List<Post> postList;

		List<Category> catList = findSubCategories(category);
		postList = postDAO.findPostsByCategory(catList);
		return postList;
	}

	public List<Post> findPostsByCategoryAndKeyword(Category category,
			String keyword) {
		List<Post> postList;

		List<Category> catList = findSubCategories(category);
		postList = postDAO.findPostsByCategoryAndKeyword(catList, keyword);
		return postList;
	}

	private List<Category> findSubCategories(Category category) {
		final List<Category> catList = new ArrayList<Category>();

		if (category == null) {
			return null;
		}

		iterateCategory(category, new Command() {
			public void execute(Category cat) {
				catList.add(cat);
			}
		});
		return catList;
	}

	interface Command {
		public void execute(Category cat);
	}

	public void addCategoryPhotoFiles(Category category, File[] photoFiles,
			String realRootPath) throws Exception {

		// create photo files
		if (photoFiles != null) {
			
			SimpleDateFormat formatter = new SimpleDateFormat(Constants.DATE_FORMAT);
			String date = formatter.format(new Date());
			
			for (File photoFile : photoFiles) {
				// generate a uuid for each photo file
				String uuid = UUID.randomUUID().toString();
				
				char dimension = 'S';
				String url = photoDAO.createPhotoFile(photoFile, date, uuid, dimension,
						realRootPath);
				Photo photo = new Photo();
				photo.setDimension(dimension);
				photo.setURL(url);
				category.addPhoto(photo);
			}
		}

	}

	public void deleteCategoryPhotoFiles(Category category,
			final String realRootPath) {
		iterateCategory(category, new Command() {
			public void execute(Category cat) {
				// delete photo files from disc
				if (cat.getPhotos() != null) {
					for (Photo p : cat.getPhotos()) {
						File photoFile = new File(realRootPath + p.getURL());
						photoFile.delete();
					}
				}
			}
		});
	}
}
